/**
 * 
 */
package neptune.web.client.view.components.dialogs;

import java.util.ArrayList;

import neptune.web.client.view.input.DefaultInputValidator;
import neptune.web.client.view.input.InputValidator;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author Roberto Bifulco [info@robertobifulco.it, robertobifulco.it]
 * 
 */
public class PropertiesDialog extends DialogBox implements ClickListener {

	private ArrayList<Label> labels = new ArrayList<Label>(0);
	private ArrayList<Widget> textBoxes = new ArrayList<Widget>(0);
	private ArrayList<InputValidator> validators = new ArrayList<InputValidator>(
			0);
	private FlowPanel infoPanel;
	private PropertiesDialogListener listener;
	private boolean modified = true;
	private String[] propertyValues;
	private DeckPanel mainPanelWrap;
	private Label messageLabel;

	public PropertiesDialog(String[] propertyNames) {

		VerticalPanel mainPanel = new VerticalPanel();
		infoPanel = new FlowPanel();

		if (propertyNames != null) {
			for (int i = 0; i < propertyNames.length; i++) {
				Label label = new Label(propertyNames[i]);
				labels.add(label);
				TextBox textBox = new TextBox();
				textBox.setName(propertyNames[i]);
				textBoxes.add(textBox);
				validators.add(new DefaultInputValidator());

				HorizontalPanel dataPanel = new HorizontalPanel();
				dataPanel.add(label);
				dataPanel.add(textBox);

				infoPanel.add(dataPanel);

				label.addStyleName("PropertiesDialog-labels");
				textBox.addStyleName("PropertiesDialog-inputs");
			}
		}
		mainPanel.add(infoPanel);

		Button okButton = new Button("Ok");
		okButton.addClickListener(this);
		Button cancelButton = new Button("Cancel");
		cancelButton.addClickListener(this);

		HorizontalPanel buttonPanel = new HorizontalPanel();
		buttonPanel.add(okButton);
		buttonPanel.add(cancelButton);

		mainPanel.add(buttonPanel);
		mainPanel.setCellHorizontalAlignment(buttonPanel,
				VerticalPanel.ALIGN_RIGHT);

		mainPanelWrap = new DeckPanel();
		mainPanelWrap.add(mainPanel);
		mainPanelWrap.add(buildProcessingView());
		mainPanelWrap.add(buildMessagePanel());

		mainPanelWrap.showWidget(0);
		this.setWidget(mainPanelWrap);

		// Styles
		this.addStyleName("PropertiesDialog");
		infoPanel.addStyleName("PropertiesDialog-infoPanel");
		okButton.addStyleName("PropertiesDialog-buttons");
		cancelButton.addStyleName("PropertiesDialog-buttons");

	}

	public void onClick(Widget sender) {
		if (((Button) sender).getText().equals("Ok")) {
			boolean error = false;
			for (int i = 0; i < textBoxes.size(); i++) {
				((Widget) textBoxes.get(i))
						.removeStyleName("PropertiesDialog-inputs-err");
			}

			String[][] values = new String[textBoxes.size()][2];
			for (int i = 0; i < textBoxes.size(); i++) {
				String[] labelValueCouple = new String[2];
				if (textBoxes.get(i) instanceof TextBox) {
					labelValueCouple[0] = ((TextBox) textBoxes.get(i))
							.getName();
					labelValueCouple[1] = ((TextBox) textBoxes.get(i))
							.getText();
					if (!((InputValidator) validators.get(i))
							.isValid(labelValueCouple[1])) {
						((TextBox) textBoxes.get(i))
								.addStyleName("PropertiesDialog-inputs-err");
						error = true;
					}

				} else if (textBoxes.get(i) instanceof PasswordTextBox) {
					labelValueCouple[0] = ((PasswordTextBox) textBoxes.get(i))
							.getName();
					labelValueCouple[1] = ((PasswordTextBox) textBoxes.get(i))
							.getText();
					if (!((InputValidator) validators.get(i))
							.isValid(labelValueCouple[1])) {
						((PasswordTextBox) textBoxes.get(i))
								.addStyleName("PropertiesDialog-inputs-err");
						error = true;
					}

				} else if (textBoxes.get(i) instanceof ListBox) {
					labelValueCouple[0] = ((ListBox) textBoxes.get(i))
							.getName();
					labelValueCouple[1] = ((ListBox) textBoxes.get(i))
							.getItemText(((ListBox) textBoxes.get(i))
									.getSelectedIndex());
					if (!((InputValidator) validators.get(i))
							.isValid(labelValueCouple[1])) {
						((ListBox) textBoxes.get(i))
								.addStyleName("PropertiesDialog-inputs-err");
						error = true;
					}
				}
				values[i] = labelValueCouple;
			}

			if (!error) {
				if (verifyIfModified(values)) {
					mainPanelWrap.showWidget(1);
					listener.okPressed(values, this);
				} else {
					this.hide();
					this.resetWindow();
				}
				return;
			} else
				return;
		}

		this.hide();
		this.resetWindow();
	}

	/**
	 * Returns the text value contained in the textbox with the given name. If
	 * no textboxes are found, returns null. If textboxes share the same name,
	 * returns the last occurence.
	 * 
	 * @param inputName
	 * @return
	 */
	public String getInput(String inputName) {
		for (int i = 0; i < textBoxes.size(); i++) {
			if (textBoxes.get(i) instanceof TextBox) {
				if (((TextBox) textBoxes.get(i)).getName().equals(inputName)) {
					return ((TextBox) textBoxes.get(i)).getText();
				}
			} else if (textBoxes.get(i) instanceof ListBox) {
				if (((ListBox) textBoxes.get(i)).getName().equals(inputName)) {
					ListBox listBox = (ListBox) textBoxes.get(i);
					return listBox.getItemText(listBox.getSelectedIndex());
				}
			} else if (textBoxes.get(i) instanceof PasswordTextBox) {
				if (((PasswordTextBox) textBoxes.get(i)).getName().equals(
						inputName)) {
					return ((PasswordTextBox) textBoxes.get(i)).getText();
				}
			}

		}
		return null;
	}

	/**
	 * Imposta il valore di un campo di input. Il campo in questione deve essere
	 * una TextBox.
	 * 
	 * @param inputName
	 * @param input
	 */
	public void setInput(String inputName, String input) {
		for (int i = 0; i < textBoxes.size(); i++) {
			if (((TextBox) textBoxes.get(i)).getName().equals(inputName))
				((TextBox) textBoxes.get(i)).setText(input);
		}
	}

	/**
	 * Imposta l'InputValidator per il dato campo di input. Il campo di input
	 * deve essere una TextBox.
	 * 
	 * @param inputName
	 * @param validator
	 */
	public void setInputValidator(String inputName, InputValidator validator) {
		for (int i = 0; i < textBoxes.size(); i++) {
			if (((TextBox) textBoxes.get(i)).getName().equals(inputName))
				validators.set(i, validator);
		}
	}

	/**
	 * Aggiunge una TextBox con nome uguale a quello della Label passata, che
	 * costituisce anche il nome visualizzato nella dialog in corrisppondenza
	 * della TextBox. L'input fornito e' convalidato dall'InputValidator passato
	 * al metodo.
	 * 
	 * @param label
	 * @param textBox
	 * @param validator
	 */
	public void addProperty(String label, TextBox textBox,
			InputValidator validator) {
		Label labelWidget = new Label(label);
		labels.add(labelWidget);

		textBox.setName(label);
		textBoxes.add(textBox);
		validators.add(validator);

		HorizontalPanel dataPanel = new HorizontalPanel();
		dataPanel.add(labelWidget);
		dataPanel.add(textBox);

		infoPanel.add(dataPanel);

		labelWidget.addStyleName("PropertiesDialog-labels");
		textBox.addStyleName("PropertiesDialog-inputs");
	}

	public void addProperty(String label, PasswordTextBox textBox,
			InputValidator validator) {
		Label labelWidget = new Label(label);
		labels.add(labelWidget);

		textBox.setName(label);
		textBoxes.add(textBox);
		validators.add(validator);

		HorizontalPanel dataPanel = new HorizontalPanel();
		dataPanel.add(labelWidget);
		dataPanel.add(textBox);

		infoPanel.add(dataPanel);
		
		labelWidget.addStyleName("PropertiesDialog-labels");
		textBox.addStyleName("PropertiesDialog-inputs");
	}

	public void addProperty(String label, ListBox listBox) {
		Label labelWidget = new Label(label);
		labels.add(labelWidget);

		
		listBox.setName(label);
		textBoxes.add(listBox);
		validators.add(new DefaultInputValidator());

		HorizontalPanel dataPanel = new HorizontalPanel();
		dataPanel.add(labelWidget);
		dataPanel.add(listBox);

		infoPanel.add(dataPanel);
		
		labelWidget.addStyleName("PropertiesDialog-labels");
		listBox.addStyleName("PropertiesDialog-inputs");
	}

	/**
	 * Imposta al valore iniziale tutti i campi della Dialog.
	 */
	public void resetWindow() {
		mainPanelWrap.showWidget(0);
		for (int i = 0; i < textBoxes.size(); i++) {
			if (textBoxes.get(i) instanceof TextBox) {
				((TextBox) textBoxes.get(i)).setText("");
			} else if (textBoxes.get(i) instanceof ListBox) {
				((ListBox) textBoxes.get(i)).setSelectedIndex(0);
			}
		}

		modified = false;
	}

	public PropertiesDialogListener getListener() {
		return listener;
	}

	public void setListener(PropertiesDialogListener listener) {
		this.listener = listener;
	}

	/**
	 * Verifica se qualche campo della dialog ha subito modifiche da parte
	 * dell'utente.
	 * 
	 * @return
	 */
	public boolean isModified() {
		return modified;
	}

	public void setModified(boolean modified) {
		this.modified = modified;
	}

	/**
	 * Assegna i valori passati nell'array ai campi della Dialog, nell'ordine in
	 * questi compaiono.
	 * 
	 * @param values
	 */
	public void setPropertyValues(String[] values) {
		if (values.length != textBoxes.size())
			return;

		propertyValues = values;

		for (int i = 0; i < textBoxes.size(); i++) {
			if (textBoxes.get(i) instanceof TextBox) {
				TextBox textBox = (TextBox) textBoxes.get(i);
				textBox.setText(propertyValues[i]);
			} else if (textBoxes.get(i) instanceof ListBox) {
				ListBox box = (ListBox) textBoxes.get(i);
				for (int j = 0; j < box.getItemCount(); j++) {
					if (box.getItemText(j).equals(propertyValues[i]))
						box.setSelectedIndex(j);
				}
			} else if (textBoxes.get(i) instanceof PasswordTextBox) {
				PasswordTextBox textBox = (PasswordTextBox) textBoxes.get(i);
				textBox.setText(propertyValues[i]);
			}
		}
	}

	private boolean verifyIfModified(String[][] newValues) {
		if (propertyValues == null)
			return true;
		for (int i = 0; i < propertyValues.length; i++) {
			if (!propertyValues[i].equals(newValues[i][1]))
				return true;
		}
		return false;
	}

	private Panel buildProcessingView() {
		Image loading = new Image("img/bigrotation2.gif"); // TODO cambiare
		// questa
		// immagine
		Label loadingLabel = new Label("Processing request...");

		VerticalPanel panel = new VerticalPanel();

		panel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);

		panel.add(loading);
		panel.add(loadingLabel);

		panel.addStyleName("AddUserPanel-processingPanel");

		return panel;
	}

	private Panel buildMessagePanel() {
		VerticalPanel panel = new VerticalPanel();

		panel.setWidth("350px");

		messageLabel = new Label();
		Button close = new Button("Close");
		close.addClickListener(this);

		panel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);

		panel.add(messageLabel);
		panel.add(close);

		panel.addStyleName("AddUserPanel-messagePanel");

		return panel;
	}

	/**
	 * Sets the message view as the active view and shown the given message
	 * 
	 * @param message
	 */
	public void showMessage(String message) {
		messageLabel.setText(message);
		messageLabel.setWidth(Integer
				.toString(mainPanelWrap.getOffsetWidth() - 20));
		mainPanelWrap.showWidget(2);
	}

}
